#ifndef COMMAND_HPP
#define COMMAND_HPP

#include <QObject>
#include <QStringList>

/**
* @brief Object representing a single line of code with all needed informations
* @details This class is used to represent a single line of the LST file \n
* Even Comment lines, blank lines, labels and EQU statements are represented with a Command \n
* The informations of the line will be splitted by Decoder and stored seperately in this class.
* @see Decoder
*
* @class Command command.hpp "command.hpp"
*/
class Command : public QObject
{
Q_OBJECT
public:

    /**
    * @brief Representing every Command
    *
    * @enum commandEnum
    */
    enum commandEnum {
	NOCOMMAND = -1,

	ADDWF = 0b00011100000000,
	ANDWF = 0b00010100000000,
	CLRF = 0b00000110000000,
	CLRW = 0b00000100000000,
	COMF = 0b00100100000000,
	DECF = 0b00001100000000,
	DECFSZ = 0b00101100000000,
	INCF = 0b00101000000000,
	INCFSZ = 0b00111100000000,
	IORWF = 0b00010000000000,
	MOVF = 0b00100000000000,
	MOVWF = 0b00000010000000,
	NOP = 0b00000000000000,
	RLF = 0b00110100000000,
	RRF = 0b00110000000000,
	SUBWF = 0b00001000000000,
	SWAPF = 0b00111000000000,
	XORWF = 0b00011000000000,

	BCF = 0b01000000000000,
	BSF = 0b01010000000000,
	BTFSC = 0b01100000000000,
	BTFSS = 0b01110000000000,

	ADDLW = 0b11111000000000,
	ANDLW = 0b11100100000000,
	CALL = 0b10000000000000,
	CLRWDT = 0b00000001100100,
	GOTO = 0b10100000000000,
	IORLW = 0b11100000000000,
	MOVLW = 0b11000000000000,
	RETFIE = 0b00000000001001,
	RETLW = 0b11010000000000,
	RETURN = 0b00000000001000,
	SLEEP = 0b00000001100011,
	SUBLW = 0b11110000000000,
	XORLW = 0b11101000000000
    };

    /**
    * @brief Representing the Type of a Command
    *
    * @enum commandType
    */
    enum commandType {COMMAND, COMMENT, LABEL, BLANK, DEFINITION, ADDITIONAL};

    /**
    * @brief Representing the different Types of Arguments
    *
    * @enum argumentType
    */
    enum argumentType {THREEBIT, SEVENBIT, EIGHTBIT, ELEVENBIT, DIRECTORYBIT};

    /**
    * @brief Default Constructor
    *
    * @fn explicit Command(QObject *parent = 0)
    * @param parent
    */
    explicit Command(QObject *parent = 0);

    /**
    * @brief Copy Constructor
    *
    * @fn Command(const Command &other)
    * @param other
    */
    Command(const Command &other);

    /**
    * @brief Destructor
    *
    * @fn ~Command
    */
    ~Command();

    Command& operator=(const Command&);

    /**
    * @brief Sets the according Adress in Program Memory for this Command
    *
    * @fn void setAdressProgramMemory(int adress)
    * @param adress
    */
    void setAdressProgramMemory(int adress);

    /**
    * @brief Sets the opCode for the Command
    *
    * @fn void setOpCode(int code)
    * @param code
    */
    void setOpCode(int code);

    /**
    * @brief Sets the arguments. They will be splitted automatically
    *
    * @fn void setArguments(int arg)
    * @param arg
    */
    void setArguments(int arg);

    /**
    * @brief Sets the Line Number of this Command
    *
    * @fn void setLineNumber(int line)
    * @param line
    */
    void setLineNumber(int line);

    /**
    * @brief Sets the Comment of this Command
    *
    * @fn void setComment(QString comment)
    * @param comment
    */
    void setComment(QString comment);

    /**
    * @brief Sets the corresponding Label
    *
    * @fn void setLabel(QString label)
    * @param label
    */
    void setLabel(QString label);

    /**
    * @brief Sets the textual representation of the Assembler Code
    *
    * @fn void setAssemblerCode(QString asmCode)
    * @param asmCode
    */
    void setAssemblerCode(QString asmCode);

    /**
    * @brief Decide which type of commands this one belongs to
    *
    * @fn void setCommandType(commandType opType)
    * @param opType
    */
    void setCommandType(commandType opType);

    /**
    * @brief Sets the command.
    *
    * @fn void setCommand(commandEnum command)
    * @param command
    */
    void setCommand(commandEnum command);

    /**
    * @brief Return the Address in Program Memory
    *
    * @fn int getAddress() const
    * @return int
    */
    int getAddress() const;

    /**
    * @brief Returns the OpCode of the command
    *
    * @fn int getOpCode() const
    * @return int
    */
    int getOpCode() const;

    /**
    * @brief Returns the Argument of the command. \n
    * There are 5 different arguments, which can be returned. All are deklared in the ArgumentType enum.
    *
    * @fn int getArgument(argumentType argument) const
    * @param argument
    * @return int
    */
    int getArgument(argumentType argument) const;

    /**
    * @brief Returns the linenumber of the command
    *
    * @fn int getLineNumber() const
    * @return int
    */
    int getLineNumber() const;

    /**
    * @brief Returns the label of the command
    *
    * @fn QString getLabel() const
    * @return QString
    */
    QString getLabel() const;

    /**
    * @brief Returns the comment of the command
    *
    * @fn QString getComment() const
    * @return QString
    */
    QString getComment() const;

    /**
    * @brief Returns the assemblercode of the command
    *
    * @fn QString getAssembler() const
    * @return QString
    */
    QString getAssembler() const;

    /**
    * @brief Returns the anchor of the command. The ancor is equal to the program counter of this command.
    *
    * @fn QString getAnchor() const
    * @return QString
    */
    QString getAnchor() const;

    /**
    * @brief Returns the type of the command.
    * There are 6 different command types.
    * @see commandType
    *
    * @fn commandType getCommandType() const
    * @return commandType
    */
    commandType getCommandType() const;

    /**
    * @brief Returns the Command
    * @see commandEnum
    *
    * @fn commandEnum getCommand() const
    * @return commandEnum
    */
    commandEnum getCommand() const;

    /**
    * @brief Extracts the command from the given opcode.
    * @see commandEnum
    *
    * @fn commandEnum extractCommand(int code) const
    * @return Command
    */
    commandEnum extractCommand(int code) const;

    /**
    * @brief Returns a String representation of the Command
    *
    * @fn QString toString() const
    * @return QString
    */
    QString toString() const;

    /**
    * @brief Sets the anchor of the command. The anchor is equal to the program counter of the command.
    *
    * @fn void setAnchor(QString anchor)
    * @param anchor
    */
    void setAnchor(QString anchor);

private:
    int adressProgramMemory;
    int opCode;
    int argumentsThreeBit;
    int argumentsSevenBit;
    int argumentsEightBit;
    int argumentsElevenBit;
    int directoryBit;
    int lineNumber;

    QString label;
    QString comment;
    QString assembler;
    QString anchor;

    commandType type;

    commandEnum command;

};

#endif // COMMAND_HPP
